package tianrun.ziguan.api.calculate.config.listener;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import tianrun.ziguan.api.calculate.config.entity.TAssetGroup;
import tianrun.ziguan.api.calculate.config.entity.TCalAsset;
import tianrun.ziguan.api.calculate.config.service.asset.group.ITAssetGroupService;
import tianrun.ziguan.api.calculate.config.service.business.RefreshCacheService;
import tianrun.ziguan.api.calculate.config.service.cal.asset.ITCalAssetService;
import tianrun.ziguan.api.calculate.config.service.common.CommonService;
import tianrun.ziguan.api.calculate.config.utils.MapUtil;
import tianrun.ziguan.api.common.util.SpringContextUtil;

import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.stream.Collectors;

@Component
public class RefreshCacheListener {
    private static Timer timer = new Timer();
    private static RefreshCacheService refreshCacheService;
    private static ITCalAssetService calAssetService;
    private static ITAssetGroupService assetGroupService;
    private static final Lock lock = new ReentrantLock();
    private static final Logger log = LoggerFactory.getLogger(RefreshCacheListener.class);
    private final static Set<String> assetGroups = ConcurrentHashMap.newKeySet();
    private final static Set<FlushByModule> modules = ConcurrentHashMap.newKeySet();
    private final static Set<Long> assetIds = ConcurrentHashMap.newKeySet();
    private final static Set<Long> groupIds = ConcurrentHashMap.newKeySet();

    public RefreshCacheListener(RefreshCacheService refreshCacheService, ITCalAssetService calAssetService, ITAssetGroupService assetGroupService) {
        RefreshCacheListener.refreshCacheService = refreshCacheService;
        RefreshCacheListener.calAssetService = calAssetService;
        RefreshCacheListener.assetGroupService = assetGroupService;
    }

    public static void flushByDeptNum(String deptNum) {
        assetGroups.add(deptNum);
        execRefresh();
    }

    private static void execRefresh() {
        timer.cancel();
        timer = new Timer();
        //log.info("清除缓存定时器");
        timer.schedule(new TimerTask() {
            @Override
            public void run() {
                lock.lock();
                CommonService commonService = SpringContextUtil.getBean(CommonService.class);

                modules.stream().collect(Collectors.groupingBy(FlushByModule::getTableName)).forEach((tableName, flushByModules) -> {
                    List<Map<String, Object>> mapList = commonService.listByIds(tableName, flushByModules.stream().map(FlushByModule::getId).collect(Collectors.toSet()), true);
                    List<Long> cal_asset_id = mapList.stream().map(map -> MapUtil.getLong(map, "cal_asset_id")).collect(Collectors.toList());
                    assetIds.addAll(cal_asset_id);
                });

                List<TCalAsset> calAssets = calAssetService.getByIds(assetIds);
                 groupIds.addAll(calAssets.stream().map(TCalAsset::getAssetGroupId).collect(Collectors.toList()));
                List<TAssetGroup> tAssetGroups = assetGroupService.getByIds(groupIds);
                assetGroups.addAll(tAssetGroups.stream().map(TAssetGroup::getName).collect(Collectors.toList()));

                HashSet<String> deptNums = new HashSet<>(assetGroups);
                assetGroups.clear();
                assetIds.clear();
                modules.clear();
                groupIds.clear();
                lock.unlock();
                deptNums.forEach(deptNum -> {
                    new Thread(() -> refreshCacheService.refreshCacheByDeptNum(deptNum)).start();
                });
            }
        }, 10000);
    }

    public static void flushByAssetId(Long id) {
        assetIds.add(id);
        execRefresh();
    }
    public static void flushByGroupId(Long id) {
        groupIds.add(id);
        execRefresh();
    }
    public static void flushByGroupIds(Set<Long> ids) {
        groupIds.addAll(ids);
        execRefresh();
    }

    public static void flushByModuleId(Long id, String tableName) {
        modules.add(new FlushByModule(id, tableName));
        execRefresh();
    }

    static class FlushByModule {
        private Long id;
        private String tableName;

        public FlushByModule(Long id, String tableName) {
            this.id = id;
            this.tableName = tableName;
        }

        public FlushByModule() {
        }

        @Override
        public boolean equals(Object o) {
            if (this == o) return true;
            if (o == null || getClass() != o.getClass()) return false;
            FlushByModule that = (FlushByModule) o;
            return Objects.equals(id, that.id) && Objects.equals(tableName, that.tableName);
        }

        @Override
        public int hashCode() {
            return Objects.hash(id, tableName);
        }

        public Long getId() {
            return id;
        }

        public void setId(Long id) {
            this.id = id;
        }

        public String getTableName() {
            return tableName;
        }

        public void setTableName(String tableName) {
            this.tableName = tableName;
        }
    }
}
